/*
 * Copyright (c) 2010-present www.walkerljl.org All Rights Reserved.
 * The software source code all copyright belongs to the author, 
 * without permission shall not be any reproduction and transmission.
 */
package org.walkerljl.practice.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * SelectSockets
 *
 * @author lijunlin<walkerljl@qq.com>
 */
public class SelectSockets {

    private static final int PORT_NUMBER = 1234;
    private ByteBuffer buffer = ByteBuffer.allocate(1024);

    /**
     * @param args
     */
    public static void main(String[] args) {
        new SelectSockets().go(args);
    }

    private void go(String[] args) {
        int port = PORT_NUMBER;
        if (args.length > 0) {
            try {
                port = Integer.parseInt(args[0]);
            } catch (Exception e) {
            }
        }

        System.out.println("Listening port: " + PORT_NUMBER);
        try {
            Selector selector = Selector.open();
            startServer(port, selector);
            while (true) {
                int n = selector.select();
                if (n == 0) {
                    continue;
                }

                Iterator<?> it = selector.selectedKeys().iterator();
                while (it.hasNext()) {
                    SelectionKey key = (SelectionKey) it.next();
                    if (key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key
                                .channel();
                        SocketChannel channel = server.accept();
                        registerChannel(selector, channel, SelectionKey.OP_READ);
                        sayHello(channel);

                    }
                    if (key.isReadable()) {
                        readDataFromChannel(key);
                    }
                }

                it.remove();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void readDataFromChannel(SelectionKey key) throws IOException {
        int count = 0;
        SocketChannel channel = (SocketChannel) key.channel();
        buffer.clear();
        while ((count = channel.read(buffer)) > 0) {
            buffer.flip();
            while (buffer.hasRemaining()) {
                System.out.println(buffer.get());
            }
            buffer.clear();
        }
        if (count < 0) {
            channel.close();
        }

    }

    private void sayHello(SocketChannel channel) throws IOException {
        if (channel == null) {
            return;
        }
        buffer.clear();
        ByteBuffer buffer = ByteBuffer.wrap("Hi, there \r\n".getBytes());
        buffer.flip();
        channel.write(buffer);
    }

    private void registerChannel(Selector selector, SocketChannel channel,
                                 int opRead) throws IOException {

        if (channel == null) {
            return;
        }

        channel.configureBlocking(false);
        channel.register(selector, opRead);
    }

    private void startServer(int port, Selector selector) throws IOException,
            ClosedChannelException {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        ServerSocket serverSocket = serverChannel.socket();
        serverSocket.bind(new InetSocketAddress(port));
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

}